import {
    _decorator,
    AssetManager,
    assetManager,
    instantiate,
    Node,
    Prefab,
    Size,
} from 'cc';
import { GUIWindow } from './GUIWindow';
import { GUIGroup } from './GUIGroup';
import { GUIPrefab } from './GUIPrefab.type';
import { GUIButton } from './GUIButton';

const { ccclass, property } = _decorator;

@ccclass('GUI')
class GUI {
    readonly GUICanvasName = 'CC-GUI-Canvas';

    guiBundle: AssetManager.Bundle = null!;

    root: GUIWindow | null = null!;

    windowArray: GUIWindow[] = [];

    async createWindows(name: string, size: Size) {
        // 加载bundle
        this.guiBundle = await this.loadBundle();
        const guiNode = await this.loadPrefab(GUIPrefab.window);

        const guiWIndow = guiNode.getComponent(GUIWindow)!;
        guiWIndow.init(name, size);

        this.root = guiWIndow;
        return this.root;
    }

    async addGroup(name: string, parent?: GUIGroup) {
        const guiNode = await this.loadPrefab(GUIPrefab.group);
        this.addContent(guiNode, parent);
        const group = guiNode.getComponent(GUIGroup)!;
        group.init(name);

        return group;
    }

    async addButton(
        name: string,
        clickFn: (param: string) => void,
        parent?: GUIGroup,
    ) {
        const guiNode = await this.loadPrefab(GUIPrefab.button);
        this.addContent(guiNode, parent);

        const button = guiNode.getComponent(GUIButton)!;
        button.init(name, clickFn);

        return button;
    }

    async loadBundle(): Promise<AssetManager.Bundle> {
        let bundle: AssetManager.Bundle =
            await new Promise<AssetManager.Bundle>((resolve, reject) => {
                assetManager.loadBundle('cc-gui', (err, data) => {
                    if (err) {
                        reject('cc-gui bundle 加载失败');
                    } else {
                        resolve(data);
                    }
                });
            });
        return bundle;
    }

    // 加载 预制件资源
    async loadPrefab(name: string) {
        const guiPrefab = await new Promise<Prefab>((resolve, reject) => {
            this.guiBundle.load<Prefab>(name, (err, data) => {
                if (err) {
                    reject(`${name} load fail ! ${err}`);
                } else {
                    resolve(data);
                }
            });
        });
        const guiNode = instantiate(guiPrefab);
        return guiNode;
    }

    private addContent(guiNode: Node, parent?: GUIGroup) {
        if (parent) {
            parent.addContent(guiNode);
        } else {
            this.root?.addContent(guiNode);
        }
    }
}

export const cc_gui = new GUI();
